#include "EnginePrivate.h"

RenderObject::RenderObject()
{
	// Create ConstantValue
	m_pConstValue_WorldViewProjMatrix = 0;
	_CreateConstantValues();

	// Create Shaders
	m_pVSShader = GShaderCompileManager.CompileVSShader("SampleHLSL.hlsl", "VSMain");
	m_pPSShader = GShaderCompileManager.CompilePSShader("SampleHLSL.hlsl", "PSMain");

	// Get Input Layout
	m_pInputLayout = GRenderStateObjectManager.GetInputLayout(INPUTLAYOUT_TPYE_POSITION3_COLOR3);
	m_VBStride = GRenderStateObjectManager.GetVBStride(INPUTLAYOUT_TPYE_POSITION3_COLOR3);

	// Get Render State Object 
	D3D11_RASTERIZER_DESC RasterizerDesc;
	RasterizerDesc.FillMode = D3D11_FILL_SOLID;
	RasterizerDesc.CullMode = D3D11_CULL_NONE;
	RasterizerDesc.FrontCounterClockwise = FALSE;
	RasterizerDesc.DepthBias = 0;
	RasterizerDesc.DepthBiasClamp = 0.0f;
	RasterizerDesc.SlopeScaledDepthBias = 0.0f;
	RasterizerDesc.DepthClipEnable = TRUE;
	RasterizerDesc.ScissorEnable = FALSE;
	RasterizerDesc.MultisampleEnable = FALSE;
	RasterizerDesc.AntialiasedLineEnable = FALSE;
	m_pRasterizerState =  GRenderStateObjectManager.GetRasterizerState(RasterizerDesc);

	D3D11_DEPTH_STENCIL_DESC DepthStencilDesc;
	DepthStencilDesc.DepthEnable = TRUE;
	DepthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	DepthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
	DepthStencilDesc.StencilEnable = FALSE;
	DepthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
	DepthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
	DepthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
	DepthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	DepthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	DepthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS ;
	DepthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
	DepthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	DepthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
	DepthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS ;
	m_pDepthStencilState = GRenderStateObjectManager.GetDepthStencilState(DepthStencilDesc);

	D3D11_BLEND_DESC BlendStateDesc;
	BlendStateDesc.AlphaToCoverageEnable = FALSE;
	BlendStateDesc.IndependentBlendEnable = FALSE;
	BlendStateDesc.RenderTarget[0].BlendEnable = FALSE;
	BlendStateDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
	BlendStateDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ZERO;
	BlendStateDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;						
	BlendStateDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE ;
	BlendStateDesc.RenderTarget[0].DestBlendAlpha=  D3D11_BLEND_ZERO ;
	BlendStateDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD ;
	BlendStateDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL ;
	m_pBlendState = GRenderStateObjectManager.GetBlendState(BlendStateDesc);

	// VB IB
	m_pVertexBuffer = 0;
	m_pIndexBuffer = 0;
}

RenderObject::~RenderObject()
{
	m_pConstValue_WorldViewProjMatrix = 0;

	m_pVSShader = 0;
	m_pPSShader = 0;

	m_pInputLayout = 0;
	m_pRasterizerState = 0;
	m_pDepthStencilState = 0;
	m_pBlendState = 0;


}

void RenderObject::Render(RenderView* pRenderView)
{
	if(!m_pVertexBuffer || !m_pIndexBuffer)
		return;

	ID3D11DeviceContext* pGD3D11Context = gEngine.GetD3DDeviceContext();

	// Set WorldViewProjMatrix
	_BuildWorldMatrix();
	Matrix4X4 WorldViewProjMatrix = m_WorldMatrix * pRenderView->m_ViewProjMatrix;
	assert(m_pConstValue_WorldViewProjMatrix);
	m_pConstValue_WorldViewProjMatrix->SetValue(&WorldViewProjMatrix);
	
	// Commit Constant Buffer
	GConstantBufferManager.CommitCB(CB_PerBatch);

	// Set Shader
	pGD3D11Context->VSSetShader(m_pVSShader, 0, 0);
	pGD3D11Context->PSSetShader(m_pPSShader, 0, 0);

	// Set Render State
	pGD3D11Context->IASetInputLayout(m_pInputLayout);
	pGD3D11Context->RSSetState(m_pRasterizerState);
	pGD3D11Context->OMSetDepthStencilState(m_pDepthStencilState, 0);
	pGD3D11Context->OMSetBlendState(m_pBlendState,0, 0xffffffff);
	pGD3D11Context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );

	// Set VB IB
	unsigned int offset = 0;
	pGD3D11Context->IASetVertexBuffers(0, 1, &m_pVertexBuffer, &m_VBStride, &offset);
	pGD3D11Context->IASetIndexBuffer(m_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);

	// Draw
	pGD3D11Context->DrawIndexed(36, 0, 0);
}

void RenderObject::_BuildWorldMatrix()
{
	m_WorldMatrix.BuildTransformMatrix(m_WorldPosition, m_Scale, m_UpVector, m_LookAtVector);
}

void RenderObject::_CreateConstantValues()
{
	ConstantBuffer* pConstantBuffer = GConstantBufferManager.GetConstantBuffer(CB_VS_PerBatch);
	assert(pConstantBuffer);
	m_pConstValue_WorldViewProjMatrix = pConstantBuffer->GetConstantValue("WorldViewProjMatrix");
	assert(m_pConstValue_WorldViewProjMatrix);
}

void RenderObject::LoadDefaultMesh()
{
	FVertex VertexList[8];
	
	VertexList[0].m_position = Vector3(-0.5, 0.5, 0.5);
	VertexList[0].m_color = Vector3(1.0, 0.0, 0.0);

	VertexList[1].m_position = Vector3(0.5, 0.5, 0.5);
	VertexList[1].m_color = Vector3(0.0, 1.0, 0.0);

	VertexList[2].m_position = Vector3(-0.5, -0.5, 0.5);
	VertexList[2].m_color = Vector3(0.0, 0.0, 1.0);

	VertexList[3].m_position = Vector3(0.5, -0.5, 0.5);
	VertexList[3].m_color = Vector3(1.0, 1.0, 0.0);

	VertexList[4].m_position = Vector3(-0.5, 0.5, -0.5);
	VertexList[4].m_color = Vector3(1.0, 1.0, 1.0);

	VertexList[5].m_position = Vector3(0.5, 0.5, -0.5);
	VertexList[5].m_color = Vector3(1.0, 0.0, 1.0);

	VertexList[6].m_position = Vector3(-0.5, -0.5, -0.5);
	VertexList[6].m_color = Vector3(0.0, 1.0, 1.0);

	VertexList[7].m_position = Vector3(0.5, -0.5, -0.5);
	VertexList[7].m_color = Vector3(0.5, 0.5, 0.5);

	for(int index = 0 ; index < 8 ; ++index)
	{
		m_vecVertexList.push_back(VertexList[index]);
	}

	unsigned short IndexList[36];
	
	IndexList[0] = 0;
	IndexList[1] = 1;
	IndexList[2] = 2;

	IndexList[3] = 1;
	IndexList[4] = 2;
	IndexList[5] = 3;

	IndexList[6] = 0;
	IndexList[7] = 4;
	IndexList[8] = 2;

	IndexList[9] = 4;
	IndexList[10] = 6;
	IndexList[11] = 2;

	IndexList[12] = 0;
	IndexList[13] = 1;
	IndexList[14] = 4;

	IndexList[15] = 1;
	IndexList[16] = 4;
	IndexList[17] = 5;

	IndexList[18] = 1;
	IndexList[19] = 3;
	IndexList[20] = 5;

	IndexList[21] = 3;
	IndexList[22] = 5;
	IndexList[23] = 7;

	IndexList[24] = 4;
	IndexList[25] = 5;
	IndexList[26] = 6;

	IndexList[27] = 5;
	IndexList[28] = 6;
	IndexList[29] = 7;

	IndexList[30] = 2;
	IndexList[31] = 3;
	IndexList[32] = 6;

	IndexList[33] = 3;
	IndexList[34] = 6;
	IndexList[35] = 7;

	for(int index = 0 ; index < 36 ; ++index)
	{
		m_vecIndexList.push_back(IndexList[index]);
	}

	HRESULT hResult;
	ID3D11Device* pGD3D11Device = gEngine.GetD3DDevice();

	D3D11_BUFFER_DESC VertexBufferDesc;
	VertexBufferDesc.ByteWidth = 4*3*2*8;
	VertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	VertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	VertexBufferDesc.CPUAccessFlags = 0;
	VertexBufferDesc.MiscFlags = 0;
	VertexBufferDesc.StructureByteStride = 0;

	D3D11_SUBRESOURCE_DATA SUBDATA;
	SUBDATA.pSysMem = &(m_vecVertexList[0]);
	SUBDATA.SysMemPitch = 0;
	SUBDATA.SysMemSlicePitch = 0;
	hResult = pGD3D11Device->CreateBuffer(&VertexBufferDesc, &SUBDATA , &m_pVertexBuffer);

	D3D11_BUFFER_DESC IndexBufferDesc;
	IndexBufferDesc.ByteWidth = 2*36;
	IndexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	IndexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	IndexBufferDesc.CPUAccessFlags = 0;
	IndexBufferDesc.MiscFlags = 0;
	IndexBufferDesc.StructureByteStride = 0;

	D3D11_SUBRESOURCE_DATA SUBIndexDATA;
	SUBIndexDATA.pSysMem = &(m_vecIndexList[0]);
	SUBIndexDATA.SysMemPitch = 0;
	SUBIndexDATA.SysMemSlicePitch = 0;
	hResult = pGD3D11Device->CreateBuffer(&IndexBufferDesc, &SUBIndexDATA , &m_pIndexBuffer);
}